<?php
/**
* @package BankLink
*/
final class DomBankLink_Paypal extends DomBankLink {
	
	/**
	 * The PayPal account of the reseller
	 * @var String
	 */
	protected $resellerAccount;
	
	/**
	 * Character encoding used in the transaction
	 * @var String
	 */
	protected $charset = 'UTF-8';
	
	/**
	 * Specifies the method by which the user is redirected to the handleReply method
	 * 0 - GET method
	 * 1 - GET method, no transaction details
	 * 2 - POST method, all transaction details
	 * @var Int
	 */
	protected $returnMethod = 2;
	
	/**
	 * Specifies the language for the log-in and billing pages at paypal.com
	 * Two character string denoting the language (Language Code, ie. US)
	 * @var String
	 */
	protected $lang = US;
	
	/**
	 * Specifies which button the user clicked. Allowed values:
	 * _xclick - direct payment
	 * _donations - donation
	 * _xclick-subscriptions - subscription 
	 * _oe-gift-certificate - buy gift certificate
	 * _s-xclick - secure direct payment
	 * @var String
	 */
	protected $cmd = '_xclick';
	
	/**
	 * Specifies whether the shipping info is required or not 
	 * 0 - asked for, but not required
	 * 1 - not asked for
	 * 2 - asked for and required
	 * @var Int
	 */
	protected $shipping = 1;
	
	/**
	 * Where the payment info will be sent
	 * @var String
	 */
	protected $serverUrl;
	
	/**
	 * Authentication token from a Paypal account. Used to identify yourself when sending PDT requests
	 * @Var String
	 */
	protected $authToken;
	
	public function getName() {
		return 'Paypal';
	}
	
	public function getKey() {
		return 'Paypal';
	}
	
	public function getIconUrl() {
		return DOM_URL . '../libsPub/DomBankLink/images/Paypal.gif';
	}
	
	public function sendToBank( DomBankLinkObject $payment ) {
		
		if( $payment instanceof DomBankPayment ) {
			$rsField = array(
				'amount'    	=> $payment->price,
				'currency_code' => strtoupper($payment->currency),
				'business'      => $this->resellerAccount,
				'item_number'   => $payment->id,
				'item_name'     => $payment->description,
				'return'     	=> $this->getCallBackUrl( $payment ),
				'cancel_return' => $this->getCallBackUrl( $payment ),
				'rm'			=> $this->returnMethod,
				'lc'			=> $this->lang,
				'charset'		=> $this->charset,
				'cmd'			=> $this->cmd,
			);
		}
        	
    	$fields = '';
    	foreach ($rsField as $ixField => $fieldValue) {
    		$fields .= '<input type="hidden" name="' . $ixField . '" value="' . htmlspecialchars($fieldValue) . '" />' . "\n";
    	}

    	$form = '
			<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
			<html xmlns="http://www.w3.org/1999/xhtml">
			<head>
			<meta http-equiv="Content-Type" content="text/html; charset='.$this->charset.'" />
			<title>Suunamine</title>
			</head>
			<body>
			<form id="form" action="'.$this->serverUrl.'" method="POST">
				'.$fields.'
				<input type="submit" value="Checkout"/>
			</form>
			<script type="text/javascript"> t = setTimeout( "document.getElementById(\"form\").submit()" ,10 ); </script>	
			</body>
			</html>';
    	
    	echo $form;
		die();
	}
	
	public function handleReplay( $paymentClassName, $requestId = NULL ) {
		
		$rsField = array();
		
		foreach ((array)$_REQUEST as $ixField => $fieldValue) {
			$rsField[$ixField] = $fieldValue;
		}
		
		$payment = DomAr::load( (int)$rsField['item_number'], $paymentClassName );
	    
	    if( !$payment )
			return false;

		//if payment is sent via PDT	
		if( $payment->confirmationStatus == 0 ) {
			
			$result = $this->confirmPDTInfo( $rsField['tx'] );
			//if info is confirmed by Paypal
			if( $result ) {
				//if email is correct and tx hasn't been used before
				if( $this->confirmInfo( $paymentClassName, $result['txn_id'], $result['receiver_email'] ) ) {
					$payment = $this->processPayment( $payment, $result );
				} else {
					$payment->confirmationStatus = 2;
					$payment->status = 4;
				}
			} else {
				$payment->confirmationStatus = 2;
				$payment->status = 4;
				
			}
		}	
	
		//if payment is sent via IPN
		if( $payment->confirmationStatus == 3 ) {
			
			//in info is confirmed by Paypal
			if( $this->confirmIPNInfo() ) {
				//if email is correct and tx hasn't been used before
				if( $this->confirmInfo( $paymentClassName, $result['txn_id'], $result['receiver_email'] ) ) {
					$payment = $this->processPayment( $payment, $rsField );
				} else {
					$payment->confirmationStatus = 2;
					$payment->status = 4;
				}
			} else {
				$payment->confirmationStatus = 2;
				$payment->status = 4;
			}
			
		} 
		
		if( !$payment->save() ) {
			throw new RuntimeException( $payment->getValidationMessages('<br>') );
		}
		
		return $payment;
	}
	
	/**
	 * Confirms that the account the payment was made to was this account and that tx has never been used before
	 */
	public function confirmInfo( $paymentClassName, $tx, $email ) {
		
		/*$txCheck = call_user_func($paymentClassName.'::dataQuery');
		
		$txCheck->select('t.tx')->where('t.tx = \''.addslashes($tx).'\'')->commit()->toArray();

		if( !empty($txCheck) ) {
			$log = new IpnLog();
			$log->post .= 'txCheck failed';
			foreach($txCheck as $k => $i) {
				$log->post .= $k.' - '.$i.'; ';
			}
			$log->post .= ' '.$tx.' '.$paymentClassName;
			$log->save();
			return false;
		}*/
		
		if( $email != $this->resellerAccount ) {
			return false;
		}
		
		return true;
	}
	
   /**
	* Confirms that the PDT info originates from paypal
	*/
	public function confirmPDTInfo( $tx ) {
		
		$post = 'cmd=_notify-synch&tx='.$tx.'&at='.$this->authToken;
		
		$curl = curl_init ($this->serverUrl);
		curl_setopt ($curl, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt ($curl, CURLOPT_HEADER, 0);
		curl_setopt ($curl, CURLOPT_TIMEOUT, 30);
		curl_setopt ($curl, CURLOPT_POST, 1);
		curl_setopt ($curl, CURLOPT_SSL_VERIFYPEER,FALSE);
		curl_setopt ($curl, CURLOPT_POSTFIELDS, $post);
		
		$result = curl_exec ($curl);
		
		if (curl_errno($curl) != 0)
			return false;
		
		curl_close($curl);	
			
		$lines = split("\n", $result);
		
		if ($lines[0] == "SUCCESS") {
			$info = array();
			foreach($lines as $i) {
				$parts = split("=", $i);
				if (count($parts)==2) {
					$info[$parts[0]] = urldecode($parts[1]);
				}
			}
			return $info;
		} else {
			return false;
		}
	}
	
	/**
	 * Confirms that the IPN info originates from Paypal
	 * MUST BE CALLED WHETHER YOU NEED TO PROCESS THE INFO OR NOT,
	 * otherwize Paypal keeps sending the info
	 */
	public function confirmIPNInfo() {
		
		$info = 'cmd=_notify-validate';
	
		foreach ( $_POST as $key => $value ) {
			$value = urlencode(stripslashes($value));
			$info .= '&'.$key.'='.$value;
		}
		
		$curl = curl_init();
		curl_setopt($curl, CURLOPT_URL, $this->serverUrl);
		curl_setopt($curl, CURLOPT_FAILONERROR, 1);
		curl_setopt($curl, CURLOPT_RETURNTRANSFER,1);
		curl_setopt($curl, CURLOPT_TIMEOUT, 30);
		curl_setopt($curl, CURLOPT_POST, 1);
		curl_setopt($curl, CURLOPT_POSTFIELDS, $info);
		
		$result = curl_exec($curl);
		
		if (curl_errno($curl) != 0)
			return false;
		
		curl_close($curl);
		
		if ( strcmp($result, "VERIFIED" ) == 0) {
			return true;
		} else {
		    return false;
		} 
	}
	
	public function processPayment( $payment, $result ) {
		
		$payment->confirmationStatus = 1;
		
		if ( $result['payment_status'] == "Failed" || $result['payment_status'] == "Denied" ){
			$payment->status = 2;
		} else if ( $result['payment_status'] == "Completed" ) {
			$payment->status = 1;
		} else if( $result['payment_status'] == "Pending" ) {
			$payment->status = 4;
		} else {
			$payment->status = 3;
		}
			
		$payment->statusDescription = $result['payment_status'];
		$payment->backTime = 'now';
		$payment->backIp = ip();
		
		if( $result['txn_id'] )
			$payment->tx = $result['txn_id'];
		
		$payment->clientAccountNr = $result['payer_id'];
		$payment->clientName = strtoupper($result['first_name'].' '.$result['last_name']);
		
		foreach( $result as $key => $i ) {
			$paymentInfo .= $key.': '.$i.'\r\n';
		}
		
		$payment->paymentInfo = $paymentInfo;
		
		return $payment;
	}
}
?>